#include "Image2D.h"

namespace egg{

    Image2D::Image2D(const Image2D& _other,bool _copy){
        mWidth=_other.mWidth;
        mHeight=_other.mHeight;
        mFormat=_other.mFormat;
        mPixelSize=_other.mPixelSize;
        if(_copy){
            mKeepBuffer=true;
            mPixels=new byte[getSize()];
            memcpy(mPixels,_other.mPixels,getSize());
        }else{
            mKeepBuffer=false;
            mPixels=_other.mPixels;
        }
    }

    Image2D::Image2D(PixelFormat _format,uint32 _w,uint32 _h){
        DevicePixelFormat dpf(_format);
        mWidth=_w;
        mHeight=_h;
        mFormat=_format;
        mKeepBuffer=true;
        mPixelSize=dpf.mSize;
        mPixels=new byte[getSize()];
    }

    Image2D::Image2D(PixelFormat _format,uint32 _w,uint32 _h,byte* _pixels){
        DevicePixelFormat dpf(_format);
        mWidth=_w;
        mHeight=_h;
        mFormat=_format;
        mPixels=_pixels;
        mPixelSize=dpf.mSize;
        mKeepBuffer=false;
    }

    Image2D::Image2D(const string& _fileName,uint32 _loadOption){
        using namespace cv;
        Mat mat=imread(_fileName,CV_LOAD_IMAGE_UNCHANGED);
        cvtColor(mat,mat,CV_BGRA2RGBA);
        mPixelSize=4;
        mWidth=mat.cols;
        mHeight=mat.rows;
        mFormat=PF_R8G8B8A8;
        mKeepBuffer=true;
        mPixels=new byte[getSize()];
        memcpy(mPixels,mat.data,getSize());

        if(_loadOption&ILO_POWER2)
            makePower2();
        if(_loadOption&ILO_FLIPY)
            flipY();
    }

    Image2D::~Image2D(){
        if(mKeepBuffer){
            delete[] mPixels;
        }
    }

    void Image2D::flipY(){
        uint32 rl=getRowLength();
        byte* temp=new byte[rl];
        uint32 s=0,e=mHeight-1;
        while(s<e){
            byte* row1=getRow(s);
            byte* row2=getRow(e);
            memcpy(temp,row1,rl);
            memcpy(row1,row2,rl);
            memcpy(row2,temp,rl);
            ++s;
            --e;
        }
        delete[] temp;
    }

    void Image2D::makePower2(){
        Image2D temp(*this);
        mWidth=Math3D::nearPower2(mWidth);
        mHeight=Math3D::nearPower2(mHeight);
        if(temp.mWidth!=mWidth&&temp.mHeight!=mHeight){
            mPixels=new byte[getSize()];
            blitFrom(temp);
        }
    }

    void Image2D::blitFrom(Image2D& _other){
        for(int x=0;x<mWidth;x++){
            for(int y=0;y<mHeight;y++){
                uint32 srcX=float(x)/float(mWidth)*_other.mWidth;
                uint32 srcY=float(y)/float(mHeight)*_other.mHeight;
                memcpy(getPixel(x,y),_other.getPixel(srcX,srcY),mPixelSize);
            }
        }
    }

    void Image2D::saveToFile(const string& fileName,uint32 saveOption){
        using namespace cv;
        Mat mat;
        mat.create(mHeight,mWidth,CV_8UC4);
        if(saveOption&ISO_FLIPY)
            flipY();
        memcpy(mat.data,mPixels,getSize());
        cvtColor(mat,mat,CV_RGBA2BGRA);
        imwrite(fileName.c_str(),mat);
    }

}